# -*- coding: iso-8859-1 -*-

if RUBY_VERSION =~ /^1\.8/ then
  class String
    def ord
      self[0]
    end
  end
end

module TeXCheck

  class FileReader
    def readlines(filename)
      IO.readlines(filename)
    end
  end

  class MemoryReader
    def initialize(files)
      @files = files
    end

    def readlines(filename)
      fail "File not found: #{filename}" unless @files.has_key?(filename)

      @files[filename]
    end

    def files
      @files.keys
    end

    def to_s
      @files.to_a.map do |fn, ls|
        [ "File: #{fn}" ] + ls + [ "\n" ]
      end.flatten.join("\n")
    end
  end
  
  class Location
    # Constructor
    # <filename>: the filename of the containing file as a string
    # <linenumber>: line index (1-based)
    def initialize(filename, linenumber)
      fail unless filename.class == String
      fail unless linenumber.class == Fixnum

      @filename = filename
      @linenumber = linenumber
    end

    attr_reader :filename
    attr_reader :linenumber

    def to_s
      "#{@filename} (#{@linenumber})"
    end

    def ==(other)
      self.filename == other.filename and self.linenumber == other.linenumber
    end

    def <=>(other)
      if self.filename == other.filename
      then self.linenumber <=> other.linenumber
      else self.filename <=> other.filename
      end
    end
  end

  class Line
    # Constructor
    # <contents> is a string representing the text on the line
    # <location> is a location object describing where the line appears in the LaTeX-document
    def initialize(contents, location)
      fail unless contents.class == String
      fail unless location.class == Location

      @contents = contents
      @location = location
    end

    # Getters for contents and location
    attr_reader :contents
    attr_reader :location

    # String representation
    def to_s
      "#{@location}: #{@contents}"
    end

    def ==(other)
      self.location == other.location
    end

    # Enables sorting
    def <=>(other)
      self.location <=> other.location
    end
  end


  # Error superclass
  class Error
    # Constructor: expects a line object
    def initialize(line)
      fail unless line.class == Line

      @line = line
    end

    # Getter method for line
    attr_reader :line

    # A string representation of the error
    def to_s
      "#{self.class.name}: #{@line}"
    end

    def ==(other)
      self.class == other.class and self.line == other.line
    end

    # To enable sorting of error objects
    def <=>(other)
      if self.class == other.class
      then self.line <=> other.line
      else self.class.name <=> other.class.name
      end
    end
  end


  # Error subclasses
  %w[ UnknownLabel MissingLabel InvalidLabel DuplicateLabel ForwardReference InvalidCharacter ].each do |constant|
    const_set(constant + "Error", Class.new(Error))
  end

end
